package com.carb.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carb.constant.MessageConstant;
import com.carb.constant.PasswordConstant;
import com.carb.context.UserContext;
import com.carb.dto.*;
import com.carb.entity.Car;
import com.carb.entity.Member;
import com.carb.entity.User;
import com.carb.enums.*;
import com.carb.exception.AccountNotFoundException;
import com.carb.exception.BusinessErrorException;
import com.carb.mapper.CarMapper;
import com.carb.mapper.MemberMapper;
import com.carb.mapper.UserMapper;
import com.carb.query.PageQueryUtils;
import com.carb.result.PageResult;
import com.carb.service.IMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carb.utils.RegexUtils;
import com.carb.vo.MemberVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 会员管理 服务实现类
 * </p>
 *
 * @author XuChaoyang
 * @since 2025-01-18
 */
@Service
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private CarMapper carMapper;

    @Resource
    private MemberMapper memberMapper;

    /**
     * 新增会员
     * @param userAddDTO 新增会员信息
     */
    @Override
    @Transactional
    public void addMember(UserAddDTO userAddDTO) {
        // 1、正则校验
        // 移动电话
        RegexUtils.checkMobilePhone(userAddDTO.getMobilePhone());
        // 身份证号码
        RegexUtils.checkIdNumber(userAddDTO.getIdNumber());
        // 电子邮箱
        RegexUtils.checkEmail(userAddDTO.getEmail());

        // 2、检查用户和会员是否已经存在且逻辑删除（已删除）
        User isUserExist = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, userAddDTO.getUsername())
                .eq(User::getDeleted, CommonDeleted.DELETED));
        if (isUserExist != null) {
            // 用户id
            Long userId = isUserExist.getId();
            // 更新用户逻辑删除为未删除
            BeanUtils.copyProperties(userAddDTO, isUserExist);
            isUserExist.setDeleted(CommonDeleted.NOT_DELETED)
                    .setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()))
                    .setCreateTime(LocalDateTime.now())
                    .setUpdateTime(LocalDateTime.now())
                    .setLastLoginTime(null);
            userMapper.update(isUserExist, Wrappers.lambdaUpdate(User.class)
                    .eq(User::getId, userId));
            // 更新会员逻辑删除为未删除
            Member isMemberExist = this.getOne(Wrappers.lambdaQuery(Member.class)
                    .eq(Member::getUserId, userId)
                    .eq(Member::getDeleted, CommonDeleted.DELETED));
            if (isMemberExist != null) {
                BeanUtils.copyProperties(userAddDTO, isMemberExist);
                isMemberExist.setDeleted(CommonDeleted.NOT_DELETED)
                        .setCreateTime(LocalDateTime.now())
                        .setUpdateTime(LocalDateTime.now())
                        .setLevel(MemberLevel.ORDINARY)
                        .setPoints(0)
                        .setBalance(0)
                        .setTotalServicesCount(0)
                        .setLastServiceTime(null);
                this.update(isMemberExist, Wrappers.lambdaUpdate(Member.class)
                        .eq(Member::getUserId, userId));
            }
            // 跳过新增逻辑
            return;
        }

        // 3、用户属性拷贝
        User user = new User();
        BeanUtils.copyProperties(userAddDTO, user);

        // 4、填充用户属性
        // 4.1、设置默认密码123456（MD5加密）
        user.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
        // 4.2、设置用户状态，默认为启用状态
        user.setStatus(CommonStatus.ENABLED);
        // 4.3、设置用户角色，当前为会员
        user.setRole(UserRole.MEMBER);

        // 5、新增用户（insert后主键会自动set到实体的id字段，只需要getId()就好）
        userMapper.insert(user);

        // 6、会员属性拷贝
        Member member = new Member();
        BeanUtils.copyProperties(userAddDTO, member);
        // 6.1、设置用户id
        member.setUserId(user.getId());

        // 6、新增会员
        this.save(member);
    }

    /**
     * 会员分页查询
     * @param memberPageQueryDTO 查询条件
     * @return 会员分页查询结果
     */
    @Override
    public PageResult<MemberVO> pageQuery(MemberPageQueryDTO memberPageQueryDTO) {
        // 1、获取查询属性
        // 1.1、分页属性
        Long pageNum = PageQueryUtils.checkPageNum(memberPageQueryDTO.getPageNum());
        Long pageSize = PageQueryUtils.checkPageSize(memberPageQueryDTO.getPageSize());
        String orderBy = memberPageQueryDTO.getOrderBy();
        Boolean isAsc = memberPageQueryDTO.getIsAsc();
        // 1.2、查询属性
        String name = memberPageQueryDTO.getName();
        CommonStatus status = memberPageQueryDTO.getStatus();
        MemberLevel level = memberPageQueryDTO.getLevel();

        // 2、构建条件
        // 2.1、分页条件
        Page<Member> page = Page.of(pageNum, pageSize);
        // 2.2、排序条件
        PageQueryUtils.applySorting(page, orderBy, isAsc);
        // 2.3、空结果
        PageResult<MemberVO> emptyPageResult = new PageResult<>(page.getTotal(), page.getPages(), Collections.emptyList());

        // 3、用户表查询（会员姓名（非空）、角色=会员、逻辑删除（未删除））
        List<User> userList = userMapper.selectList(Wrappers.lambdaQuery(User.class)
                .like(name != null, User::getName, name)
                .eq(status != null, User::getStatus, status)
                .eq(User::getRole, UserRole.MEMBER)
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));
        if (userList.isEmpty()) return emptyPageResult;

        // 4、构造用户id与用户对象的映射关系
        Map<Long, User> userMap = new HashMap<>();
        List<Long> userIds = new ArrayList<>();
        for (User user : userList) {
            userIds.add(user.getId());
            userMap.put(user.getId(), user);
        }

        // 5、会员表查询（会员用户id=用户id、会员等级（非空）、逻辑删除（未删除））
        Page<Member> memberPage = this.page(page, Wrappers.lambdaQuery(Member.class)
                .in(Member::getUserId, userIds)
                .eq(level != null, Member::getLevel, level)
                .eq(Member::getDeleted, CommonDeleted.NOT_DELETED));

        // 6、封装VO数据列表
        List<MemberVO> memberVOList = new ArrayList<>();
        for (Member member : memberPage.getRecords()) {
            User user = userMap.get(member.getUserId());
            MemberVO memberVO = getMemberVO(member, user);
            memberVOList.add(memberVO);
        }

        // 7、将实体分页对象转换为VO分页对象
        Page<MemberVO> memberVOPage = PageQueryUtils.convertToVOPage(memberPage, memberVOList);

        // 8、返回封装结果
        return new PageResult<>(memberVOPage.getTotal(), memberVOPage.getPages(), memberVOList);
    }

    /**
     * 根据会员id查询会员信息
     * @param id 会员id
     * @return 查询结果
     */
    @Override
    public MemberVO getMemberById(Long id) {
        // 1、检查会员是否存在
        Member member = checkMemberExist(id);

        // 2、根据用户id查询用户信息
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getId, member.getUserId())
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));

        // 3、封装VO并返回
        return getMemberVO(member, user);
    }

    /**
     * 修改会员信息
     * @param memberUpdateDTO 修改的会员信息
     */
    @Override
    @Transactional
    public void updateMember(MemberUpdateDTO memberUpdateDTO) {
        // 1、检查会员是否存在
        Long memberId = memberUpdateDTO.getId();
        Member member = checkMemberExist(memberId);

        // 2、会员更新信息（移动电话、身份证号码、电子邮箱需要进行正则校验）
        // 移动电话
        String mobilePhone = memberUpdateDTO.getMobilePhone();
        RegexUtils.checkMobilePhone(mobilePhone);
        // 身份证号码
        String idNumber = memberUpdateDTO.getIdNumber();
        RegexUtils.checkIdNumber(idNumber);
        // 电子邮箱
        String email = memberUpdateDTO.getEmail();
        RegexUtils.checkEmail(email);

        // 3、用户更新
        User user = new User();
        BeanUtils.copyProperties(memberUpdateDTO, user);
        Long userId = member.getUserId();
        user.setId(userId).setUpdateTime(LocalDateTime.now());
        userMapper.update(user, Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, userId));

        // 4、会员更新（只需要修改更新时间（自动填充））
        this.update(new Member(), Wrappers.lambdaUpdate(Member.class)
                .eq(Member::getId, memberId));
    }

    /**
     * 获取当前登录会员信息
     * @return 查询结果
     */
    @Override
    public MemberVO getMemberByUserId(Long userId) {
        // 1、根据用户id查询会员id
        Long memberId = memberMapper.getMemberIdsByUserIds(List.of(userId)).getFirst();
        // 2、根据会员id查询会员信息
        return this.getMemberById(memberId);
    }

    /**
     * 当前登录会员余额充值
     * @param amount 充值金额（整数，单位为元）
     */
    @Override
    @Transactional
    public void rechargeBalanceForMember(Integer amount) {
        // 1、获取当前登录会员对象
        Long userId = UserContext.getUserId();
        Member member = this.getOne(Wrappers.lambdaQuery(Member.class)
                .eq(Member::getUserId, userId)
                .eq(Member::getDeleted, CommonDeleted.NOT_DELETED));

        // 2、检查充值金额是否正确
        if (amount <= 0) {
            throw new BusinessErrorException(MessageConstant.RECHARGE_AMOUNT_ERROR);
        }

        // 3、更新会员余额
        Integer newBalance = amount * 100 + member.getBalance();
        this.update(new Member(), Wrappers.lambdaUpdate(Member.class)
                .eq(Member::getId, member.getId())
                .set(Member::getBalance, newBalance));
    }

    /**
     * 当前登录会员升级
     * @param memberLevel 会员等级
     */
    @Override
    @Transactional
    public void upgradeCurrentMember(MemberLevel memberLevel) {
        // 1、获取当前登录会员对象
        Long userId = UserContext.getUserId();
        Member member = this.getOne(Wrappers.lambdaQuery(Member.class)
                .eq(Member::getUserId, userId)
                .eq(Member::getDeleted, CommonDeleted.NOT_DELETED));

        // 2、检查会员等级，只允许升级为更高等级
        if (member.getLevel().getCode() >= memberLevel.getCode()) {
            throw new BusinessErrorException(MessageConstant.ALREADY_HIGHER_LEVEL);
        }

        // 3、升级所需积分
        Integer needPoints = switch (memberLevel) {
            case ORDINARY -> 0;     // 普通0积分
            case SILVER  -> 648;    // 银卡648积分
            case GOLD    -> 3240;   // 金卡3240积分
            case SUPREME -> 6480;   // 至尊6480积分
        };

        // 4、检查会员积分是否足够
        if (member.getPoints() < needPoints) {
            throw new BusinessErrorException(MessageConstant.MEMBER_POINTS_NOT_ENOUGH_);
        }

        // 5、升级会员等级
        this.update(new Member(), Wrappers.lambdaUpdate(Member.class)
                .eq(Member::getId, member.getId())
                .set(Member::getLevel, memberLevel)
                .set(Member::getPoints, member.getPoints() - needPoints));
    }

    /**
     * 删除会员
     * @param id 会员id
     */
    @Override
    @Transactional
    public void deleteMember(Long id) {
        // 1、检查会员是否存在
        Member member = checkMemberExist(id);

        // 2、删除会员（逻辑删除）
        this.update(new Member(), Wrappers.lambdaUpdate(Member.class)
                .eq(Member::getId, id)
                .set(Member::getDeleted, CommonDeleted.DELETED));

        // 3、删除会员关联的车辆信息（逻辑删除）
        carMapper.update(new Car(), Wrappers.lambdaUpdate(Car.class)
                .eq(Car::getMemberId, id)
                .set(Car::getDeleted, CommonDeleted.DELETED));

        // 4、删除用户（逻辑删除）
        userMapper.update(new User(), Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, member.getUserId())
                .set(User::getDeleted, CommonDeleted.DELETED));
    }

    /**
     * 会员余额充值
     * @param id 会员id
     * @param amount 充值金额（整数，单位为元）
     */
    @Override
    @Transactional
    public void rechargeBalance(Long id, Integer amount) {
        // 1、检查充值金额是否正确
        if (amount <= 0) {
            throw new BusinessErrorException(MessageConstant.RECHARGE_AMOUNT_ERROR);
        }

        // 2、检查会员是否存在
        Member member = checkMemberExist(id);

        // 3、更新会员余额
        Integer newBalance = amount * 100 + member.getBalance();
        this.update(new Member(), Wrappers.lambdaUpdate(Member.class)
                .eq(Member::getId, id)
                .set(Member::getBalance, newBalance));
    }

    /**
     * 会员注册
     * @param memberRegisterDTO 会员注册信息
     */
    @Override
    @Transactional
    public void memberRegister(MemberRegisterDTO memberRegisterDTO) {
        UserAddDTO userAddDTO = new UserAddDTO();
        BeanUtils.copyProperties(memberRegisterDTO, userAddDTO);
        this.addMember(userAddDTO);
    }

    /**
     * 检查会员是否存在
     * @param memberId 会员id
     * @return 会员对象
     */
    private Member checkMemberExist(Long memberId) {
        Member member = this.getOne(Wrappers.lambdaQuery(Member.class)
                .eq(Member::getId, memberId)
                .eq(Member::getDeleted, CommonDeleted.NOT_DELETED));
        if (member == null) {
            // 会员账号不存在，抛出异常
            throw new AccountNotFoundException(MessageConstant.MEMBER_ACCOUNT_NOT_FOUND);
        }
        return member;
    }

    /**
     * 封装MemberVO
     * @param member 员工信息
     * @param user 用户信息
     * @return MemberVO
     */
    private MemberVO getMemberVO(Member member, User user) {
        MemberVO memberVO = new MemberVO();
        BeanUtils.copyProperties(member, memberVO);
        memberVO.setUsername(user.getUsername())
                .setName(user.getName())
                .setGender(user.getGender())
                .setAge(user.getAge())
                .setMobilePhone(user.getMobilePhone())
                .setIdNumber(user.getIdNumber())
                .setEmail(user.getEmail())
                .setAddress(user.getAddress())
                .setAvatarUrl(user.getAvatarUrl())
                .setStatus(user.getStatus())
                .setLastLoginTime(user.getLastLoginTime());
        return memberVO;
    }

}
